 /*******************************************************************************
  * Copyright (c) 2000, 2005 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.core.internal.indexing;

 class IndexedStoreContext extends IndexedStoreObject {

     public static final int SIZE = 32;
     public static final int TYPE = 2;

     /*
      The open number field is no longer used to generate object ids, but may not be deleted since a non-zero
      open number indicates that the object number field has not been initialized.
      */
     private static final int OpenNumberOffset = 2;
     private static final int OpenNumberLength = 4;
     private Field openNumberField;
     private int openNumber;

     private static final int ObjectDirectoryAddressOffset = 6;
     private static final int ObjectDirectoryAddressLength = 4;
     private Field objectDirectoryAddressField;
     private ObjectAddress objectDirectoryAddress;

     private static final int IndexDirectoryAddressOffset = 10;
     private static final int IndexDirectoryAddressLength = 4;
     private Field indexDirectoryAddressField;
     private ObjectAddress indexDirectoryAddress;

     private static final int ObjectNumberOffset = 14;
     private static final int ObjectNumberLength = 8;
     private Field objectNumberField;
     private long objectNumber;

     /**
      * Constructs a new context.
      */
     IndexedStoreContext() {
         super();
         indexDirectoryAddress = ObjectAddress.Null;
         objectDirectoryAddress = ObjectAddress.Null;
         openNumber = 0;
         objectNumber = 0;
     }

     /**
      * Constructs a context from a field read from the store.
      */
     IndexedStoreContext(Field f, ObjectStore store, ObjectAddress address) throws ObjectStoreException {
         super(f, store, address);
     }

     /**
      * Sets the fields definitions as subfields of a contents field.
      */
     protected void setFields(Field contents) {
         openNumberField = contents.subfield(OpenNumberOffset, OpenNumberLength);
         objectDirectoryAddressField = contents.subfield(ObjectDirectoryAddressOffset, ObjectDirectoryAddressLength);
         indexDirectoryAddressField = contents.subfield(IndexDirectoryAddressOffset, IndexDirectoryAddressLength);
         objectNumberField = contents.subfield(ObjectNumberOffset, ObjectNumberLength);
     }

     /**
      * Places the contents of the buffer into the fields.
      * Subclasses should implement and call super.
      */
     protected void extractValues(Field contents) throws ObjectStoreException {
         super.extractValues(contents);
         setFields(contents);
         openNumber = openNumberField.getInt();
         objectDirectoryAddress = new ObjectAddress(objectDirectoryAddressField.get());
         indexDirectoryAddress = new ObjectAddress(indexDirectoryAddressField.get());
         objectNumber = objectNumberField.getLong();
         /* here is where we transition to using object numbers -- upward compatible change */
         if (openNumber > 0) {
             objectNumber = (long) openNumber << 32;
             openNumber = 0;
             setChanged();
         }
     }

     /**
      * Places the contents of the fields into the buffer.
      * Subclasses should implement and call super.
      */
     protected void insertValues(Field contents) {
         super.insertValues(contents);
         setFields(contents);
         openNumberField.put(openNumber);
         objectDirectoryAddressField.put(objectDirectoryAddress);
         indexDirectoryAddressField.put(indexDirectoryAddress);
         objectNumberField.put(objectNumber);
     }

     /**
      * Returns the index directory address from the buffer.
      */
     ObjectAddress getIndexDirectoryAddress() {
         return indexDirectoryAddress;
     }

     /**
      * Returns the minimum size of this object's instance -- including its type field.
      * Subclasses should override.
      */
     protected int getMinimumSize() {
         return SIZE;
     }

     /**
      * Returns the object directory address from the buffer.
      */
     ObjectAddress getObjectDirectoryAddress() {
         return objectDirectoryAddress;
     }

     /**
      * Returns the required type of this class of object.
      * Subclasses must override.
      */
     protected int getRequiredType() {
         return TYPE;
     }

     /**
      * Generates and returns the next object number. This is essentially the
      * count of the number of user-defined objects generated in this store.
      */
     long getNextObjectNumber() {
         objectNumber++;
         setChanged();
         return objectNumber;
     }

     /**
      * Sets the index directory address.
      */
     void setIndexDirectoryAddress(ObjectAddress address) {
         this.indexDirectoryAddress = address;
         setChanged();
     }

     /**
      * Sets the object directory address.
      */
     void setObjectDirectoryAddress(ObjectAddress address) {
         this.objectDirectoryAddress = address;
         setChanged();
     }

     /**
      * Provides a printable representation of this object.
      */
     public String toString() {
         StringBuffer b = new StringBuffer ();
         b.append("Context("); //$NON-NLS-1$
 b.append(objectNumber);
         b.append(","); //$NON-NLS-1$
 b.append(indexDirectoryAddress);
         b.append(","); //$NON-NLS-1$
 b.append(objectDirectoryAddress);
         b.append(")"); //$NON-NLS-1$
 return b.toString();
     }

 }

